package com.excel.util;

import com.google.common.collect.Maps;
import org.springframework.util.ObjectUtils;

import javax.annotation.Nonnull;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author User
 */
public class StreamUtil {


    private StreamUtil() {}

    public static <T> void doIfNotEmp(T obj, Consumer<T> consumer) {
        if (!isEmp(obj)) {
            consumer.accept(obj);
        }
    }

    public static <T> void doEach(List<T> list, Consumer<T> consumer) {
        if (!isEmp(list)) {
            list.stream().filter(Objects::nonNull).forEach(consumer);
        }
    }

    private static <T> boolean isEmp(T obj) {
        if (obj == null) {
            return true;
        }
        if (obj instanceof Collection) {
            return ((Collection<?>) obj).isEmpty();
        }
        if (obj instanceof Map) {
            return ((Map<?, ?>) obj).isEmpty();
        }
        if (obj instanceof String) {
            return ((String) obj).isEmpty();
        }
        return false;
    }

    /**
     * 方便使用, list 为空直接返回空结果, 并自动过滤 map->null的值
     */
    public static <T, R> List<R> mapToList(Collection<T> list, Function<T, R> func) {
        if (isEmp(list)) {
            return new ArrayList<>();
        }
        return list.stream().filter(Objects::nonNull).map(func).filter(Objects::nonNull).collect(Collectors.toList());
    }

    /**
     * 方便使用, list 为空直接返回空结果, 并自动过滤 map->null的值
     */
    public static <T, R> List<R> mergeList(Collection<T> list, Function<T, List<R>> func) {
        if (isEmp(list)) {
            return new ArrayList<>();
        }
        return list.stream()
                .filter(Objects::nonNull)
                .map(func)
                .filter(it -> !ObjectUtils.isEmpty(it))
                .flatMap(Collection::stream)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 方便使用, list 为空直接返回空结果, 并自动过滤 map->null的值
     */
    public static <T, R> Set<R> mergeListToSet(Collection<T> list, Function<T, List<R>> func) {
        if (isEmp(list)) {
            return new HashSet<>();
        }
        return list.stream()
                .filter(Objects::nonNull)
                .map(func)
                .filter(it -> !ObjectUtils.isEmpty(it))
                .flatMap(Collection::stream)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
    }

    /**
     * 方便使用, list 为空直接返回空结果, 并自动过滤 map->null的值
     */
    public static <T, R> Set<R> mapToSet(Collection<T> list, Function<T, R> func) {
        if (isEmp(list)) {
            return new HashSet<>();
        }
        return list.stream().filter(Objects::nonNull).map(func).filter(Objects::nonNull).collect(Collectors.toCollection(HashSet::new));
    }

    /**
     * 分组
     *
     * @param idFunc idFunc
     */
    public static <T, R> Map<R, T> toMap(Collection<T> list, Function<T, R> idFunc) {
        if (isEmp(list)) {
            return new HashMap<>();
        }
        return list.stream().filter(Objects::nonNull).collect(Collectors.toMap(idFunc, Function.identity(), (a, b) -> a));
    }

    /**
     * 分组
     *
     * @param idFunc idFunc
     */
    public static <T, R> Map<R, T> toLinkedMap(Collection<T> list, Function<T, R> idFunc) {
        if (isEmp(list)) {
            return new HashMap<>();
        }
        return list.stream().filter(Objects::nonNull).collect(Collectors.toMap(idFunc, Function.identity(), (a, b) -> a, LinkedHashMap::new));
    }

    /**
     * 分组
     *
     * @param idFunc idFunc
     */
    public static <T, R, K, S extends Comparable<S>> Map<R, K> toLinkedMap(
            List<T> list, Function<T, R> idFunc, Function<T, K> valueFunc, Function<T, S> sortFunc) {
        if (isEmp(list)) {
            return Maps.newLinkedHashMap();
        }
        list.sort(Comparator.comparing(sortFunc));
        return list.stream().filter(Objects::nonNull).collect(
                Collectors.toMap(
                        idFunc,
                        valueFunc,
                        (a, b) -> a,
                        LinkedHashMap::new
                )
        );
    }

    /**
     * 分组
     *
     * @param idFunc idFunc
     */
    public static <T, R, K> Map<R, K> toMap(Collection<T> list, Function<T, R> idFunc, Function<T, K> valueFunc) {
        if (isEmp(list)) {
            return Maps.newHashMap();
        }
        return list.stream().filter(Objects::nonNull).collect(Collectors.toMap(idFunc, valueFunc, (a, b) -> a));
    }

    /**
     * 分组
     *
     * @param idFunc idFunc
     */
    public static <T, R, K> Map<R, K> toLinkedMap(Collection<T> list, Function<T, R> idFunc, Function<T, K> valueFunc) {
        if (isEmp(list)) {
            return Maps.newHashMap();
        }
        return list.stream().filter(Objects::nonNull).collect(Collectors.toMap(idFunc, valueFunc, (a, b) -> a, LinkedHashMap::new));
    }

    /**
     * 分组
     *
     * @param idFunc idFunc
     */
    public static <T, R> Map<R, List<T>> groupBy(Collection<T> list, Function<T, R> idFunc) {
        if (isEmp(list)) {
            return Maps.newHashMap();
        }
        return list.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(idFunc));
    }

    /**
     * 分组有序
     *
     * @param idFunc idFunc
     */
    public static <T, R> Map<R, List<T>> groupByOrder(Collection<T> list, Function<T, R> idFunc) {
        if (isEmp(list)) {
            return Maps.newHashMap();
        }
        return list.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(idFunc, LinkedHashMap::new, Collectors.toList()));
    }

    /**
     * 分组
     *
     * @param idFunc idFunc
     */
    public static <T, R> Map<R, List<T>> groupByUseLinked(Collection<T> list, Function<T, R> idFunc) {
        if (isEmp(list)) {
            return Maps.newHashMap();
        }
        return list.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(idFunc, LinkedHashMap::new, Collectors.toList()));
    }

    public static <T> List<T> filter(Collection<T> list, Predicate<T> predicate) {
        if (isEmp(list)) {
            return new ArrayList<>();
        }
        return list.stream().filter(predicate).collect(Collectors.toList());
    }

    /**
     * 移除集合中所有为 null 的元素
     */
    public static <T> List<T> removeNull(Collection<T> list) {
        if (isEmp(list)) {
            return new ArrayList<>();
        }
        return list.stream().filter(Objects::nonNull).collect(Collectors.toList());
    }

    /**
     * 如果 两个值的id相同, 则用 target 替换list中的值
     */
    public static <T> List<T> replace(@Nonnull List<T> list, @Nonnull T target, Function<? super T, Object> func) {
        if (isEmp(list)) {
            return new ArrayList<>();
        }
        return list.stream().map(it -> {
            if (ObjectUtils.nullSafeEquals(func.apply(it), func.apply(target))) {
                return target;
            }
            return it;
        }).collect(Collectors.toList());
    }

    /**
     * 如果 两个值的id相同, 则用 target 替换list中的值, 如果都不同, 则添加在list末尾
     */
    public static <T> List<T> replaceOrAdd(@Nonnull List<T> list, @Nonnull T target, Function<? super T, Object> func) {
        AtomicBoolean isEquals = new AtomicBoolean(false);
        List<T> collect = list.stream().map(it -> {
            if (ObjectUtils.nullSafeEquals(func.apply(it), func.apply(target))) {
                isEquals.set(true);
                return target;
            }
            return it;
        }).collect(Collectors.toList());

        if (!isEquals.get()) {
            collect.add(target);
        }
        return collect;
    }

    public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }


    /**
     * 根据 keyExtractor.apply(list) 的值去去重
     */
    public static <T> List<T> distinctByKey(List<T> list, Function<? super T, Object> keyExtractor) {
        if (isEmp(list)) {
            return new ArrayList<>();
        }
        return StreamUtil.filter(list, StreamUtil.distinctByKey(keyExtractor));
    }

    /**
     * 先过滤在执行
     *
     * @param list      集合
     * @param predicate 判断
     * @param consumer  执行
     */
    public static <T> List<T> filterThenDo(List<T> list, Predicate<T> predicate, Consumer<T> consumer) {
        if (isEmp(list)) {
            return new ArrayList<>();
        }
        return list.stream().filter(predicate)
                .peek(consumer)
                .collect(Collectors.toList());
    }


    public static <T> Boolean anyMatch(Collection<T> collection, Predicate<? super T> predicate) {
        if (isEmp(collection)) {
            return Boolean.FALSE;
        }
        return collection.stream().anyMatch(predicate);
    }


    public static <T> Boolean allMatch(Collection<T> collection, Predicate<? super T> predicate) {
        if (isEmp(collection)) {
            return Boolean.FALSE;
        }
        return collection.stream().allMatch(predicate);
    }


}
